runtime: nanosecond monotonic clock; fix Linux clock IDs#2015
Open
cpunion wants to merge 1 commit into
Open
Conversation
9d14354 to
ea66de5
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
The monotonic time source had two problems: - On Linux, runtimeNano passed clite's CLOCK_MONOTONIC, whose value is Darwin's clock id (6). Linux interprets 6 as CLOCK_MONOTONIC_COARSE, a millisecond-granularity clock: consecutive time.Now() readings were identical 100% of the time and the smallest nonzero delta was 1ms. - On Darwin, clock_gettime(CLOCK_MONOTONIC) itself only has microsecond granularity (96% identical consecutive readings, 1us minimum delta). Mirror Go's runtime structure with a per-OS nanotime1 in the runtime package itself, keeping the hot path free of clite indirection and clite unchanged: Darwin reads CLOCK_UPTIME_RAW through clock_gettime_nsec_np (the same clock Go's nanotime uses there), Linux uses clock_gettime with the OS-correct CLOCK_MONOTONIC id as a local constant, and remaining platforms keep the previous behavior. Measured with consecutive time.Now() deltas (min nonzero / zero-frac): - macOS arm64: 1us / 96.5% -> 41ns / 26% (Go 1.26: 41ns / 22%) - Linux arm64: 1ms / 100% -> 41ns / 21% time.Sleep, Timer and Ticker behave identically before and after. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ea66de5 to
0271395
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The monotonic time source had two independent problems:
runtimeNanopassed clite'sCLOCK_MONOTONIC, whose value is Darwin's clock id (6). Linux interprets 6 asCLOCK_MONOTONIC_COARSE, a millisecond-granularity clock: consecutivetime.Now()readings were identical 100% of the time and the smallest nonzero delta was 1ms. Timer precision, sync spin timing and any benchmark that truststime.Sincewere all millisecond-quantized.clock_gettime(CLOCK_MONOTONIC)itself only has microsecond granularity (96% identical consecutive readings, 1µs minimum delta).Changes
Mirror Go's runtime structure with a per-OS
nanotime1in the runtime package itself, keeping the hot path free of clite indirection and clite unchanged:CLOCK_UPTIME_RAWthroughclock_gettime_nsec_np— the same clock Go'snanotimeuses there — via a direct C linkname.clock_gettimewith the OS-correctCLOCK_MONOTONICid as a local constant.Validation
Consecutive
time.Now()delta probe (min nonzero delta / fraction of zero deltas), 200k iterations:time.Sleep/Timer/Tickersmoke: 50ms sleep → 51ms, 30ms timer → 31ms, 3×10ms ticker → 32ms, identical before and after.go test ./test/go -run 'Select|Channel'passes on macOS; builds and probes verified in the Linux arm64 container.Found while benchmarking #2012: cold-path metrics on Linux read as 0ns because the monotonic clock could not resolve sub-millisecond durations.
🤖 Generated with Claude Code